/********************************************************************************
 * Copyright (c) 2019 [Open Lowcode SAS](https://openlowcode.com/)
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0 .
 *
 * SPDX-License-Identifier: EPL-2.0
 ********************************************************************************/

package org.openlowcode.server.data.properties;

import org.openlowcode.server.data.DataObject;
import org.openlowcode.server.data.DataObjectPayload;
import org.openlowcode.server.data.DataObjectProperty;
import org.openlowcode.server.data.storage.StoredField;

/**
 * A property providing a name to an object. A name is a short, potentially non
 * unique description of a business object. The name can be generated by an
 * auto-naming rule
 * 
 * @author <a href="https://openlowcode.com/" rel="nofollow">Open Lowcode
 *         SAS</a>
 *
 * @param <E> data object this is applied to
 */
public class Named<E extends DataObject<E>> extends DataObjectProperty<E> {
	private StoredField<String> objectname;
	@SuppressWarnings("unused")
	private Uniqueidentified<E> uniqueidentified;
	private NamedDefinition<E> nameddefinition;

	@SuppressWarnings("unchecked")
	public Named(NamedDefinition<E> definition, DataObjectPayload parentpayload) {
		super(definition, parentpayload);
		objectname = (StoredField<String>) this.field.lookupOnName("OBJECTNAME");
		this.nameddefinition = definition;
	}

	/**
	 * sets the name to the new object without persistence. The object should be
	 * persisted by performing an update
	 * 
	 * @param object object to apply the name on
	 * @param name   new name
	 */
	public void setobjectname(E object, String name) {
		if (nameddefinition.getAutonamingRule() != null)
			throw new RuntimeException(" this function can be called only if autonaming property is not set");
		if (name!=null) if (name.length() > NamedDefinition.NAMED_LENGTH)
			throw new RuntimeException("name is too long");
		this.objectname.setPayload(name);

	}

	/**
	 * gets the object name
	 * 
	 * @return the object name
	 */
	public String getObjectname() {
		return this.objectname.getPayload();
	}

	/**
	 * sets dependent property unique identified
	 * 
	 * @param uniqueidentified uniqueidentified property for the same object
	 */
	public void setDependentPropertyUniqueidentified(Uniqueidentified<E> uniqueidentified) {
		this.uniqueidentified = uniqueidentified;

	}

	/**
	 * performs pre-processing to dataobject insert. This means generating the name
	 * if autonaming business rules is activated
	 * 
	 * @param object the object to perform pre-processing on
	 */
	public void preprocStoredobjectInsert(E object) {
		if (nameddefinition.getAutonamingRule() == null)
			throw new RuntimeException(" this function can be called only if autonaming property is set");
		this.objectname.setPayload(nameddefinition.getAutonamingRule().generateName(object));

	}

	/**
	 * performs pre-processing to dataobject update. This means generating the name
	 * again if auto-naming business rule is activated as the name may change if
	 * other information on the object changes
	 * 
	 * @param object the object to perform pre-processing on
	 */
	public void preprocUniqueidentifiedUpdate(E object) {
		if (nameddefinition.getAutonamingRule() == null)
			throw new RuntimeException(" this function can be called only if autonaming property is set");
		this.objectname.setPayload(nameddefinition.getAutonamingRule().generateName(object));

	}

	/**
	 * A massive treatment for insert pre-processing.
	 * 
	 * @param object            batch of object
	 * @param preprocnamedbatch batch of object named property
	 */
	public static <E extends DataObject<E>> void preprocStoredobjectInsert(E[] object, Named<E>[] preprocnamedbatch) {
		if (object == null)
			throw new RuntimeException("object array is null, this is not supported");
		if (preprocnamedbatch == null)
			throw new RuntimeException("preprocnamedbatch array is null, this is not supported");
		if (object.length != preprocnamedbatch.length)
			throw new RuntimeException(
					"Object length " + object.length + " is different from named length" + preprocnamedbatch.length);

		for (int i = 0; i < object.length; i++) {
			E thisobject = object[i];
			Named<E> namedproperty = preprocnamedbatch[i];
			if (namedproperty.nameddefinition.getAutonamingRule() == null)
				throw new RuntimeException(
						" this function can be called only if autonaming property is set for index = " + i);
			namedproperty.objectname
					.setPayload(namedproperty.nameddefinition.getAutonamingRule().generateName(thisobject));
		}

	}

	/**
	 * massive treatment for update pre-processing
	 * 
	 * @param object            batch of objects to process
	 * @param preprocnamedbatch batch of named properties of the objects
	 */
	public static <E extends DataObject<E>> void preprocUniqueidentifiedUpdate(E[] object,
			Named<E>[] preprocnamedbatch) {
		preprocStoredobjectInsert(object, preprocnamedbatch);

	}
}
